package pilebis;

import java.util.ArrayList;

import javax.swing.JFrame;

public class Environnement {

	public ArrayList<Poignee> pile;
	public ArrayList<Classe> types;
	public ArrayList<Variable> instances;
	public int cptPoignees;
	
	public Environnement(){
		this.pile = new ArrayList<Poignee>();
		this.types = new ArrayList<Classe>();
		this.instances = new ArrayList<Variable>();
		this.cptPoignees = 0;
	}
	
	public void createVariable(String typename){
		Classe typeclasse = this.getClasseByName(typename);
		if(typeclasse!=null){
			this.createVariable(typeclasse);
		}
	}
	
	public void createVariable(Classe type){
		String nomvar = type.nomClasse + cptPoignees;
		Variable newvar = new Variable(type, nomvar);
		String nompgn = "p"+cptPoignees;
		Poignee newpgn = new Poignee(newvar, nompgn, cptPoignees);
		newvar.poignees.add(newpgn);
		this.pile.add(newpgn);
		this.instances.add(newvar);
		/* il faut ajouter les attributs de la nouvelle variable dans la liste de variables
		 * de l'environnement. Autrement, la suppression de la nouvelle variable entrainerait
		 * la suppression de tous ses attributs qui pourraient etre lies a une ou des poignees,
		 * ce qui serait absurde
		 * Il faut juste verifier que l'objet dans la liste instances est le meme que celui present dans
		 * la liste d'attributs de la variable en faisant des tests dans le main, faire des modifications
		 * sur l'un qui devraient entrainer les memes modifications sur l'autre */
		this.addAttributesToInstances(newvar);
		cptPoignees++;
		/*
		if(!type.isPrimitive){
			for(int k=0; k<type.typesAttributs.size(); k++){
				this.createVariable(type.typesAttributs.get(k));
		*/
				/* on pourrait compter le nombre de variables creees 
				 * afin d'ensuite afficher ce nombre comme l'avait suggere Mauran */
		/*
			}
		}
		*/
	}
	
	public void addAttributesToInstances(Variable var){
		if(!var.type.isPrimitive){
			for(int k=0; k<var.attributs.size(); k++){
				this.instances.add(var.attributs.get(k));
				this.addAttributesToInstances(var.attributs.get(k));
			}
		}
	}
	
	public Variable getVariableByName(String namevar){
		Variable res = null;
		for(int k = 0; k<this.instances.size(); k++){
			if(this.instances.get(k).name.equals(namevar)){
				res = this.instances.get(k);
			}
		}
		return res;
	}
	
	public Classe getClasseByName(String classname){
		Classe res = null;
		int k = 0;
		boolean found = false;
		while((k<this.types.size()) && (!found)){
			if(this.types.get(k).nomClasse.equals(classname)){
				res = this.types.get(k);
				found = true;
			}
			k++;
		}
		return res;
	}
	
	public Poignee getPoigneeByName(String namepgn){
		Poignee res = null;
		for(int k = 0; k<this.pile.size(); k++){
			if(this.pile.get(k).nom.equals(namepgn)){
				res = this.pile.get(k);
			}
		}
		return res;
	}
	
	public void equalsPoigneePoignee(String namepgnleft, String namepgnright){
		Poignee pgnleft = this.getPoigneeByName(namepgnleft);
		Poignee pgnright = this.getPoigneeByName(namepgnright);
		if((pgnleft!=null) && (pgnright!=null) && (pgnleft.typepgn.nomClasse.equals(pgnright.typepgn.nomClasse))){
			if(pgnright.pointeVers!=null){
				if(pgnleft.pointeVers!=null){
					pgnleft.pointeVers.retirePoignee(pgnleft.nom);
				}
				pgnright.pointeVers.poignees.add(pgnleft);
				pgnleft.pointeVers = pgnright.pointeVers;
			}else{
				if(pgnleft.pointeVers!=null){
					pgnleft.pointeVers.retirePoignee(pgnleft.nom);
					pgnleft.pointeVers = null;
				}
			}
		}
	}
	
	public void equalsPoigneeVariable(String namepgn, String namevar){
		Poignee pgn = this.getPoigneeByName(namepgn);
		Variable var = this.getVariableByName(namevar);
		if(pgn.typepgn.nomClasse.equals(var.type.nomClasse)){
			if(pgn.pointeVers!=null){
				pgn.pointeVers.retirePoignee(namepgn);
				pgn.pointeVers = null;
			}
			var.poignees.add(pgn);
			pgn.pointeVers = var;
		}
	}
	
	public void mettrePoigneeNull(String namepgn){
		Poignee pgn = this.getPoigneeByName(namepgn);
		if(pgn.pointeVers!=null){
			pgn.pointeVers.retirePoignee(namepgn);
			pgn.pointeVers = null;
		}
	}
	
	public boolean attributeOfLinkedVariable(String varname){
		int k = 0;
		boolean res = false;
		while(k<this.instances.size() && !res){
			Variable var_k = this.instances.get(k);
			int p = 0;
			while(p<var_k.attributs.size() && !res){
				res = var_k.attributs.get(p).name.equals(varname);
				p++;
			}
			k++;
		}
		return res;
	}
	
	public void ramasseMiettes(){
		/* supprime les variables sans poignees. Il se peut qu'une variable non primitive
		 * ne soit liee a aucune poignee mais que certains de ses attributs le soient */
		int k = 0;
		while(k < this.instances.size()){
			if(this.instances.get(k).poignees.isEmpty() && !this.attributeOfLinkedVariable(this.instances.get(k).name)){
				this.instances.remove(k);
			}else{
				k++;
			}
		}
	}
	
	public static void main(String[] args) {
	
		Classe entier = new Classe("int", true);
		Classe point = new Classe("Point", false);
		point.nomsAttributs.add("x");
		point.nomsAttributs.add("y");
		point.typesAttributs.add(entier);
		point.typesAttributs.add(entier);
		Classe segment = new Classe("Segment", false);
		segment.nomsAttributs.add("pointA");
		segment.nomsAttributs.add("pointB");
		segment.typesAttributs.add(point);
		segment.typesAttributs.add(point);
		
		Environnement env = new Environnement();
		env.types.add(segment);
		env.types.add(point);
		env.types.add(entier);
		
		//env.createVariable("Segment");
		//env.createVariable("Point");
		/*
		env.equalsPoigneeVariable("p1","Segment0.pointB");
		env.mettrePoigneeNull("p0");
		env.ramasseMiettes();
		env.instances.get(0).attributs.get(0).name = "N'IMPORTE QUOI";
		*/
		for(int k=0; k<env.instances.size(); k++){
			System.out.println(env.instances.get(k).name);
		}
		for(int k=0; k<env.pile.size(); k++){
			if(env.pile.get(k).pointeVers!=null){
				System.out.println(env.pile.get(k).nom+" -> "+env.pile.get(k).pointeVers.name);
			}else{
				System.out.println(env.pile.get(k).nom + " -> null");
			}
		}
		
		DrawEnvironnement drawenv = new DrawEnvironnement(env);
		GUI gui = new GUI(drawenv);
		gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		gui.setVisible(true);
		
	}
}
